<?php
/**
 * 微信授权登录
 * User: 我想有个家
 * Date: 2019/6/14
 * Time: 14:23
 */

namespace App\Service;


use App\Log;
use Hyperf\Contract\ConfigInterface;

class WechatAuthLogin {
    private $appid;
    private $appSecret;
    private $redirect_uri;

    public function __construct(ConfigInterface $config) {
        $wx = $config->get('md.wechat');
        $this->appid = $wx['appid'];
        $this->appSecret = $wx['appSecret'];
        $this->redirect_uri = urlencode($wx['callbackUrl']);
    }

    /**
     * 获取跳转地址
     * @return string
     */
    public function getUrl() {
        $state = $this->getState();
        return "https://open.weixin.qq.com/connect/qrconnect?appid={$this->appid}&redirect_uri={$this->redirect_uri}&response_type=code&scope=snsapi_login&state={$state}#wechat_redirect";
    }

    /**
     * 获取用户信息accessToken
     * @param $code
     * @return mixed
     * @throws \Exception
     */
    public function getAccessToken($code) {
        // code获得access_token
        $url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$this->appid}&secret={$this->appSecret}&code={$code}&grant_type=authorization_code";
        $info = json_decode(file_get_contents($url), true);
        if (empty($info)) {
            $this->log('微信登录', ['微信服务连接异常']);
            throw new \Exception('微信登录异常');
        }
        if (isset($info['errcode'])) {
            $this->log('获取eccesstoken异常', $info);
            throw new \Exception('微信登录异常');
        }
        return $info;
    }

    /**
     * 获取用户信息
     * @param $accessToken array
     * @return bool|array
     * @throws \Exception
     */
    public function getUserInfoByAccessToken($accessToken) {
        // 获取用户信息
        $url = "https://api.weixin.qq.com/sns/userinfo?access_token={$accessToken['access_token']}&openid={$accessToken['openid']}";
        $info = json_decode(file_get_contents($url), true);
        if (empty($info)) {
            $this->log('微信登录', ['微信服务连接异常']);
            throw new \Exception('微信登录异常');
        }
        if (isset($info['errcode'])) {
            $this->log('获取userinfo异常', $info);
            throw new \Exception('微信登录异常');
        }
        $info['nickname'] = mb_substr(filterEmoji($info['nickname']), 0, 20);
        return [
            'openid' => $info['openid'],
            'unionid' => $info['unionid'],
            'nickname' => mb_substr(filterEmoji($info['nickname']), 0, 20),
            'headimgurl' => $info['headimgurl']
        ];
    }

    /**
     * @param string $message
     * @param array $context
     */
    private function log(string $message, array $context) {
        Log::get('wx_login')->error($message, $context);
    }

    /**
     * 直接获取用户信息
     * @param $code
     * @return array|bool
     * @throws \Exception
     */
    public function getUserInfo($code) {
        return $this->getUserInfoByAccessToken($this->getAccessToken($code));
    }


    /**
     * 生成唯一随机串防CSRF攻击
     * @return string
     */
    private function getState() {
        return md5(uniqid(rand(), TRUE));
    }
}
